/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.compomics.proteomusicplayer.MS2;

import com.compomics.util.experiment.massspectrometry.Peak;
import com.compomics.util.experiment.massspectrometry.Spectrum;
import com.compomics.util.experiment.massspectrometry.SpectrumFactory;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import org.jfugue.Pattern;
import org.jfugue.PatternListener;
import org.jfugue.Player;
import org.jfugue.Rhythm;
import uk.ac.ebi.jmzml.xml.io.MzMLUnmarshallerException;

/**
 *
 * @author Kenneth
 */
public class SpectrumPlayer {

    private static double maxIntensity;
    private static double noiseThresHold;
    private static final String[] notes = {"A", "B", "C", "D", "E", "F", "G"};

    public static void main(String[] args) throws URISyntaxException, IOException, IllegalArgumentException, MzMLUnmarshallerException {
        File mgf = new File("C:\\Users\\Kenneth\\Documents\\Projects\\testing_repo\\Pride_FTP\\11954\\pride_exp_complete_ac_11954.mgf");
        //demo
        playSpectrumFile(mgf);

    }

    public static void playSpectrumFile(File mgf) throws IOException, MzMLUnmarshallerException {
        SpectrumFactory factory = SpectrumFactory.getInstance();
        factory.clearFactory();
        factory.addSpectra(mgf, null);
        ArrayList<String> spectrumTitles = factory.getSpectrumTitles(mgf.getName());
        // Play the song!
        for (String aSpectrumTitle : spectrumTitles) {
            Spectrum aSpectrum = factory.getSpectrum(mgf.getName(), aSpectrumTitle);
            playSpectrum(aSpectrum);
        }
    }

    public static void playSpectrum(Spectrum aSpectrum) throws IOException, MzMLUnmarshallerException {
        final Player songPlayer = new Player();
        Pattern song = new Pattern();
        getSpectrumParameters(aSpectrum);
        final Pattern songPattern = sampleSpectrumSound(aSpectrum);
        final Pattern noisePattern = sampleSpectrumNoise(aSpectrum);
        //make the patterns equal length
        song.add(songPattern);
        song.add(noisePattern);
        songPlayer.play(song);
    }

    private static Pattern sampleSpectrumNoise(Spectrum aSpectrum) {
        Rhythm rhythm = new Rhythm();
        rhythm.setLayer(1, convertNoiseToRhytmn(aSpectrum));
        rhythm.addSubstitution('1', "[BASS_DRUM]i");
        rhythm.addSubstitution('3', "Rs [BASS_DRUM]s");
        rhythm.addSubstitution('5', "[ACOUSTIC_SNARE]i");
        rhythm.addSubstitution('7', "[PEDAL_HI_HAT]s Rs");
        rhythm.addSubstitution('9', "[CRASH_CYMBAL_1]s Rs");
        rhythm.addSubstitution('0', "Ri");
        rhythm.addSubstitution('2', "Ri");
        rhythm.addSubstitution('4', "Ri");
        rhythm.addSubstitution('6', "Ri");
        rhythm.addSubstitution('8', "Ri");
        return rhythm.getPattern();
    }

    private static Pattern sampleSpectrumSound(Spectrum aSpectrum) {
        StringBuilder mainSong = new StringBuilder("I[PIANO]");
        for (Peak aPeak : aSpectrum.getPeakList()) {
            if (aPeak.getIntensity() > noiseThresHold) {
                mainSong.append(convertPeakToNote(aPeak)).append(" ");
            }
        }
        return new Pattern(mainSong.substring(0, mainSong.lastIndexOf(" ")));
    }

    private static String convertNoiseToRhytmn(Spectrum aSpectrum) {
        StringBuilder rhytmMaker = new StringBuilder();
        for (Peak aPeak : aSpectrum.getPeakList()) {
            if (aPeak.getIntensity() <= noiseThresHold) {
                rhytmMaker.append(aPeak.getIntensity() / aPeak.getMz());
            }
        }
        return rhytmMaker.toString();
    }

    private static void getSpectrumParameters(Spectrum aSpectrum) {
        maxIntensity = aSpectrum.getMaxIntensity();
        noiseThresHold = maxIntensity / 10;
    }

    private static String convertPeakToNote(Peak peak) {
        String letter = notes[Math.min((int) Math.ceil(10 * peak.getIntensity() / maxIntensity), notes.length - 1)];
        String length = "5";
        String pitch = "h";
        return letter + length + pitch;
    }

}
